package com.jml.zookeeper.二期.分布式锁;

import java.util.concurrent.CountDownLatch;
import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.ZkClient;

/**
 * @author:jml
 * @date: 2019/12/9 10:25
 * @description：
 */
//是一个多例，释放锁就是断开连接，不主动删除节点
public class ZkTemplzateImplLock extends AbstractTemplzateLock {
	
	//参数1 连接地址
	private static final String ADDRES = "172.16.5.118:2181";
	// 参数2 zk超时时间
	private static final int TIMEOUT = 5000;
	// 创建我们的zk连接
	private ZkClient zkClient = new ZkClient(ADDRES, TIMEOUT);
	/**
	 * 共同的创建临时节点，这个可以写枚举，根据不同的逻辑用不同的节点名字
	 */
	private String lockPath = "/lockPath";
	private CountDownLatch countDownLatch = null;

    @Override
    protected boolean tryLock() {
	    // 获取锁的思想：多个jvm同时创建临时节点，只要谁能够创建成功 谁能够获取到锁
	    try {
		    zkClient.createEphemeral(lockPath);
		    return true;
	    } catch (Exception e) {
            // 如果创建已经存在的话
//            e.printStackTrace();
		    return false;
	    }
    }

    @Override
    protected void waitLock() {
	    // 1.使用事件监听 监听lockPath节点是否已经被删除，如果被删除的情况下 有可以重新的进入到获取锁的权限
	    IZkDataListener iZkDataListener = new IZkDataListener() {
		    @Override
		    public void handleDataChange(String s, Object o) throws Exception {
			
		    }
		
		    @Override
		    public void handleDataDeleted(String s) throws Exception {
			    if (countDownLatch != null) {
				    countDownLatch.countDown();// 计数器变为0
			    }
			
		    }
	    };
	    zkClient.subscribeDataChanges(lockPath, iZkDataListener);
	    // 2.使用countDownLatch等待
	    if (countDownLatch == null) {
		    countDownLatch = new CountDownLatch(1);
	    }
	    try {
		    countDownLatch.await();// 如果当前计数器不是为0 就一直等待
	    } catch (Exception e) {
		
	    }
	    // 3. 删除监听
	    zkClient.unsubscribeDataChanges(lockPath, iZkDataListener);
    }

    @Override
    protected void unImplLock() {
	    if (zkClient != null) {
		    zkClient.close();
		    System.out.println(Thread.currentThread().getName() + "，释放了锁>>>");
	    }
    }
}
